#pragma once
#include<iostream>
#include<algorithm>
#include"MemUtil.h"
#include"BasicType.h"
#include"LocInfo.h"
#include"IO.h"
using namespace std;

enum IndexOpType{INDDEL, INDADD};

class IndexRecord{
public:
    Basic* opVal; //T是basic子类指针
    LocInfo* locInfo;
    IndexOpType indexOpType;


    void init(Basic* opVal, LocInfo* locInfo, IndexOpType indexOpType){
        this->opVal = opVal;
        this->locInfo = locInfo;
        this->indexOpType = indexOpType;
    }

    IndexRecord(Basic* opVal, LocInfo* locInfo, IndexOpType indexOpType){
        init(opVal, locInfo, indexOpType);
    }


    IndexRecord(const char* byteData, const TYPE& dataType){
        const int32_t& dataLen = BasicUtil::getDataSize(dataType);

        opVal = BasicUtil::byteDataToBasicData(&byteData[0], dataType);
        locInfo = new LocInfo(&byteData[dataLen]);
        memcpy(&indexOpType, &byteData[dataLen + LocInfo::getLocInfoSize()], sizeof (IndexOpType));
    }

    //析构函数里面都是同步释放 仅在最头部控制异步
    ~IndexRecord(){
        MemUtil::clearPtrMem(opVal);
        MemUtil::clearPtrMem(locInfo);
    }

    char* getByteData(){
        char* byteData = new char[getIndexRecordSize(opVal->getType())];
        memcpy(&byteData[0], opVal->getByteData(), Basic::dataMaxLen);
        memcpy(&byteData[Basic::dataMaxLen], locInfo, LocInfo::getLocInfoSize());
        memcpy(&byteData[Basic::dataMaxLen + LocInfo::getLocInfoSize()], &indexOpType, sizeof (IndexOpType));
        return byteData;
    }

    static int32_t getIndexRecordSize(const TYPE& dataType){
        return BasicUtil::getDataSize(dataType) +
               LocInfo::getLocInfoSize() +
               sizeof (IndexOpType);
    }
};


bool isSameData(const IndexRecord* indRec1, const IndexRecord* indRec2){
    if( basicEqu(indRec1->opVal, indRec2->opVal) &&
        *(indRec1->locInfo) == *(indRec2->locInfo)){
        return true;
    }
    return false;
}


bool indRecCmp(const IndexRecord* indRec1, const IndexRecord* indRec2){
    const Basic* opVal1 = indRec1->opVal;
    const Basic* opVal2 = indRec2->opVal;
    if(!(basicEqu(opVal1, opVal2))){
        return basicCmp(opVal1, opVal2);
    }
    const LocInfo* locInfo1 = indRec1->locInfo;
    const LocInfo* locInfo2 = indRec2->locInfo;
    if(!(*locInfo1 == *locInfo2)){
        return *locInfo1 < *locInfo2;
    }
    return indRec1->indexOpType < indRec2->indexOpType;
}


pair<int, int> getDelAddCount(const vector<IndexRecord*>& recVec){
    int delCount = 0;
    for(IndexRecord* rec : recVec){
        if(rec->indexOpType == INDADD){
            break;
        }
        delCount++;
    }
    return make_pair(delCount, recVec.size() - delCount);
}


class IndexRecordUtil{

private:

    static void addToNewIndexRecords(vector<IndexRecord*>& newRecVec, vector<IndexRecord*>& tmpRecVec){
        IndexRecord* firstRec = tmpRecVec.front();
        if(tmpRecVec.size() == 1){      //在全局模式下仅有一条记录那么一定是ADD 无需处理
            newRecVec.push_back(firstRec);      //仅有一个记录 无需化简 直接添加
            //释放 无需清空
            tmpRecVec.clear();
        }
        else{
            const pair<int, int>& pair = getDelAddCount(tmpRecVec);
            //first是删除次数 second是添加次数
            if(pair.first < pair.second){   //当添加次数大于删除次数 化简为添加
                newRecVec.push_back(new IndexRecord(firstRec->opVal,
                                                    firstRec->locInfo,
                                                    INDADD));
            }
            else if(pair.first > pair.second){  //当添加次数小于删除次数 化简为删除
                newRecVec.push_back(new IndexRecord(firstRec->opVal,
                                                    firstRec->locInfo,
                                                    INDDEL));
            }
            //移交两个数据所有权
            firstRec->opVal = nullptr;
            firstRec->locInfo = nullptr;
            MemUtil::asyncClearVecMem(tmpRecVec);
            //列表可能立马就要使用 同步清空 里面记录异步释放
            tmpRecVec.clear();
        }
    }


public:
    //获取优化后的记录vec 旧vec中没有复用的record被释放
    static vector<IndexRecord*> getOptimizIndexRecordVec(vector<IndexRecord*>& recVec, const bool& isSorted){
        if(recVec.empty()){ return {}; }
        //给记录排序
        if(!isSorted){ sort(recVec.begin(), recVec.end(), indRecCmp); }
        vector<IndexRecord*> optimizVec;
        vector<IndexRecord*> tmpVec;
        for(IndexRecord* tmpRec : recVec){
            if(!tmpVec.empty() && !isSameData(tmpVec.back(), tmpRec)){
                addToNewIndexRecords(optimizVec, tmpVec);
            }
            tmpVec.push_back(tmpRec);
        }
        addToNewIndexRecords(optimizVec, tmpVec);
        return optimizVec;
    }


    //写这么丑不调用Record的getByteData是为了少一次拷贝
    static char* getIndRecVecByteData(const vector<IndexRecord*>& records, const TYPE& dataType){
        if(records.empty()){ return nullptr; }
        char* byteData = new char[records.size() * IndexRecord::getIndexRecordSize(dataType)];
        int32_t opDataLen = BasicUtil::getDataSize(dataType), locInfoSize = LocInfo::getLocInfoSize();
        int64_t loc = 0;
        for(IndexRecord* indRec : records){
            const int16_t& blockNo = indRec->locInfo->getBlockNo();
            const int& opInd = indRec->locInfo->getInd();
            memcpy(&byteData[loc], indRec->opVal->getByteData(), opDataLen);
            loc += opDataLen;
            memcpy(&byteData[loc], &blockNo, sizeof (blockNo));
            loc += sizeof (blockNo);
            memcpy(&byteData[loc], &opInd, sizeof (opInd));
            loc += sizeof (opInd);
            memcpy(&byteData[loc], &(indRec->indexOpType), sizeof (IndexOpType));
            loc += sizeof (IndexOpType);
        }
        return byteData;
    }

    static vector<IndexRecord*> byteDataToIndRecVec(const char* byteData, const int64_t& dataLen, const TYPE& dataType){
        vector<IndexRecord*> resVec;
        const int32_t& recSize = IndexRecord::getIndexRecordSize(dataType);
        for(int tmpInd = 0; tmpInd < dataLen; tmpInd += recSize){
            resVec.push_back(new IndexRecord(&byteData[tmpInd], dataType));
        }
        return resVec;
    }

    static vector<vector<IndexRecord*>> mutexReadRecVec(fstream& f, const int64_t& effectLoc, const TYPE& dataType){
        const int64_t& dataStartLoc = sizeof (int64_t) * 3, dataLen = effectLoc - dataStartLoc;
        char* byteData = new char[dataLen];
        f.seekg(dataStartLoc, ios::beg);
        f.read(byteData, dataLen);
        vector<vector<IndexRecord*>> resVec;
        int64_t tmpDataLen;
        for(int tmpInd = 0; tmpInd < dataLen; ){
            memcpy((char*)&tmpDataLen, &byteData[tmpInd], sizeof (tmpDataLen));
            tmpInd += sizeof (tmpDataLen);
            resVec.push_back(byteDataToIndRecVec(&byteData[tmpInd], tmpDataLen, dataType));
            tmpInd += tmpDataLen;
        }
        MemUtil::asyncClearPtrArrMem(byteData);
        return resVec;
    }

    static vector<IndexRecord*> mergeRecVec(const vector<vector<IndexRecord*>>& unMergeRecVec){
        const int32_t& vecCount = unMergeRecVec.size();
        vector<int32_t> indVec(vecCount, 0);
        vector<IndexRecord*> resVec;
        while(true){
            int32_t chosenVecInd = -1;
            IndexRecord* chosenRec = nullptr;
            for(int tmpVecInd = 0; tmpVecInd < vecCount; tmpVecInd++){
                const vector<IndexRecord*>& tmpVec = unMergeRecVec[tmpVecInd];
                const int32_t& tmpInd = indVec[tmpVecInd];
                if( tmpInd < tmpVec.size() &&
                    (chosenRec == nullptr ||
                    indRecCmp(tmpVec[tmpInd], chosenRec)))
                {
                    chosenRec = tmpVec[tmpInd];
                    chosenVecInd = tmpVecInd;
                }
            }
            if(chosenRec == nullptr){ break; }
            resVec.push_back(chosenRec);
            indVec[chosenVecInd]++;
        }
        return resVec;
    }
};




